"""initial schema"""

from alembic import op
import sqlalchemy as sa


revision = "202502100001"
down_revision = None
branch_labels = None
depends_on = None


relationship_status_enum = sa.Enum("pending", "active", "revoked", name="relationship_status")
diary_visibility_enum = sa.Enum("private", "shared", "partner_only", name="diary_visibility")
cycle_phase_enum = sa.Enum("menstruation", "luteal", "follicular", "fertile", "safe", name="cycle_phase")
anniversary_recurrence_enum = sa.Enum("once", "monthly", "yearly", "custom", name="anniversary_recurrence")


def upgrade() -> None:
  op.create_table(
    "users",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("email", sa.String(length=255), nullable=False),
    sa.Column("username", sa.String(length=64), nullable=False),
    sa.Column("password_hash", sa.String(length=255), nullable=False),
    sa.Column("is_active", sa.Boolean(), nullable=False, server_default=sa.text("1")),
    sa.Column("verified_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("prefs_json", sa.JSON(), nullable=True),
    sa.Column("active_relationship_id", sa.Integer(), nullable=True),
    sa.UniqueConstraint("email"),
    sa.UniqueConstraint("username"),
  )
  op.create_index("ix_users_email", "users", ["email"], unique=False)
  op.create_index("ix_users_username", "users", ["username"], unique=False)

  op.create_table(
    "relationships",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("initiator_id", sa.Integer(), nullable=False),
    sa.Column("partner_id", sa.Integer(), nullable=True),
    sa.Column("status", relationship_status_enum, nullable=False, server_default="pending"),
    sa.Column("invite_code", sa.String(length=32), nullable=False),
    sa.Column("confirmed_at", sa.DateTime(timezone=True), nullable=True),
    sa.ForeignKeyConstraint(["initiator_id"], ["users.id"], ondelete="CASCADE"),
    sa.ForeignKeyConstraint(["partner_id"], ["users.id"], ondelete="SET NULL"),
    sa.UniqueConstraint("invite_code", name="uq_relationship_invite_code"),
  )
  op.create_index("ix_relationships_initiator_id", "relationships", ["initiator_id"], unique=False)
  op.create_index("ix_relationships_partner_id", "relationships", ["partner_id"], unique=False)

  op.create_foreign_key(
    "fk_users_active_relationship_id_relationships",
    "users",
    "relationships",
    ["active_relationship_id"],
    ["id"],
    ondelete="SET NULL",
  )

  op.create_table(
    "partner_profiles",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("partner_name", sa.String(length=120), nullable=True),
    sa.Column("relationship_start_date", sa.DateTime(), nullable=True),
    sa.Column("timezone", sa.String(length=64), nullable=True),
    sa.Column("notification_prefs_json", sa.JSON(), nullable=True),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
    sa.UniqueConstraint("user_id"),
  )

  op.create_table(
    "diary_entries",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("relationship_id", sa.Integer(), nullable=True),
    sa.Column("title", sa.String(length=180), nullable=False),
    sa.Column("content_md", sa.Text(), nullable=False),
    sa.Column("mood", sa.String(length=32), nullable=True),
    sa.Column("tags_json", sa.JSON(), nullable=True),
    sa.Column("ai_summary", sa.Text(), nullable=True),
    sa.Column("visibility", diary_visibility_enum, nullable=False, server_default="shared"),
    sa.ForeignKeyConstraint(["relationship_id"], ["relationships.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
  )
  op.create_index("ix_diary_entries_user_id", "diary_entries", ["user_id"], unique=False)
  op.create_index("ix_diary_entries_relationship_id", "diary_entries", ["relationship_id"], unique=False)

  op.create_table(
    "anniversaries",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("relationship_id", sa.Integer(), nullable=True),
    sa.Column("name", sa.String(length=160), nullable=False),
    sa.Column("date", sa.Date(), nullable=False),
    sa.Column("recurrence", anniversary_recurrence_enum, nullable=False, server_default="yearly"),
    sa.Column("reminder_offset_days", sa.Integer(), nullable=False, server_default="7"),
    sa.ForeignKeyConstraint(["relationship_id"], ["relationships.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
  )
  op.create_index("ix_anniversaries_user_id", "anniversaries", ["user_id"], unique=False)
  op.create_index("ix_anniversaries_relationship_id", "anniversaries", ["relationship_id"], unique=False)

  op.create_table(
    "cycle_logs",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("relationship_id", sa.Integer(), nullable=True),
    sa.Column("start_date", sa.Date(), nullable=False),
    sa.Column("end_date", sa.Date(), nullable=True),
    sa.Column("symptoms_json", sa.JSON(), nullable=True),
    sa.Column("notes", sa.Text(), nullable=True),
    sa.ForeignKeyConstraint(["relationship_id"], ["relationships.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
  )
  op.create_index("ix_cycle_logs_user_id", "cycle_logs", ["user_id"], unique=False)
  op.create_index("ix_cycle_logs_relationship_id", "cycle_logs", ["relationship_id"], unique=False)

  op.create_table(
    "cycle_predictions",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("log_id", sa.Integer(), nullable=True),
    sa.Column("relationship_id", sa.Integer(), nullable=True),
    sa.Column("phase", cycle_phase_enum, nullable=False),
    sa.Column("start_date", sa.Date(), nullable=False),
    sa.Column("end_date", sa.Date(), nullable=False),
    sa.Column("confidence", sa.Float(), nullable=False, server_default="0.7"),
    sa.ForeignKeyConstraint(["log_id"], ["cycle_logs.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["relationship_id"], ["relationships.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
  )
  op.create_index("ix_cycle_predictions_user_id", "cycle_predictions", ["user_id"], unique=False)
  op.create_index("ix_cycle_predictions_relationship_id", "cycle_predictions", ["relationship_id"], unique=False)

  op.create_table(
    "auth_sessions",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("refresh_token", sa.String(length=512), nullable=False),
    sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False),
    sa.Column("user_agent", sa.String(length=255), nullable=True),
    sa.Column("ip_address", sa.String(length=64), nullable=True),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
    sa.UniqueConstraint("refresh_token"),
  )
  op.create_index("ix_auth_sessions_user_id", "auth_sessions", ["user_id"], unique=False)

  op.create_table(
    "ai_sessions",
    sa.Column("id", sa.Integer(), primary_key=True, index=True),
    sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
    sa.Column("user_id", sa.Integer(), nullable=False),
    sa.Column("relationship_id", sa.Integer(), nullable=True),
    sa.Column("thread_id", sa.String(length=80), nullable=False),
    sa.Column("context_json", sa.JSON(), nullable=False),
    sa.ForeignKeyConstraint(["relationship_id"], ["relationships.id"], ondelete="SET NULL"),
    sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"),
  )
  op.create_index("ix_ai_sessions_thread_id", "ai_sessions", ["thread_id"], unique=False)
  op.create_index("ix_ai_sessions_relationship_id", "ai_sessions", ["relationship_id"], unique=False)


def downgrade() -> None:
  op.drop_index("ix_ai_sessions_relationship_id", table_name="ai_sessions")
  op.drop_index("ix_ai_sessions_thread_id", table_name="ai_sessions")
  op.drop_table("ai_sessions")

  op.drop_index("ix_auth_sessions_user_id", table_name="auth_sessions")
  op.drop_table("auth_sessions")

  op.drop_index("ix_cycle_predictions_relationship_id", table_name="cycle_predictions")
  op.drop_index("ix_cycle_predictions_user_id", table_name="cycle_predictions")
  op.drop_table("cycle_predictions")

  op.drop_index("ix_cycle_logs_relationship_id", table_name="cycle_logs")
  op.drop_index("ix_cycle_logs_user_id", table_name="cycle_logs")
  op.drop_table("cycle_logs")

  op.drop_index("ix_anniversaries_relationship_id", table_name="anniversaries")
  op.drop_index("ix_anniversaries_user_id", table_name="anniversaries")
  op.drop_table("anniversaries")

  op.drop_index("ix_diary_entries_relationship_id", table_name="diary_entries")
  op.drop_index("ix_diary_entries_user_id", table_name="diary_entries")
  op.drop_table("diary_entries")

  op.drop_table("partner_profiles")

  op.drop_constraint("fk_users_active_relationship_id_relationships", "users", type_="foreignkey")

  op.drop_index("ix_relationships_partner_id", table_name="relationships")
  op.drop_index("ix_relationships_initiator_id", table_name="relationships")
  op.drop_table("relationships")

  op.drop_index("ix_users_username", table_name="users")
  op.drop_index("ix_users_email", table_name="users")
  op.drop_table("users")

  cycle_phase_enum.drop(op.get_bind(), checkfirst=False)
  diary_visibility_enum.drop(op.get_bind(), checkfirst=False)
  anniversary_recurrence_enum.drop(op.get_bind(), checkfirst=False)
  relationship_status_enum.drop(op.get_bind(), checkfirst=False)
